package com.zeyu.framework.modules.sys.utils;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.zeyu.framework.core.security.SystemAuthorizingRealm;
import com.zeyu.framework.core.security.utils.SecurityUtils;
import com.zeyu.framework.modules.sys.dao.MenuDao;
import com.zeyu.framework.modules.sys.dao.OfficeDao;
import com.zeyu.framework.modules.sys.dao.RoleDao;
import com.zeyu.framework.modules.sys.dao.UserDao;
import com.zeyu.framework.modules.sys.entity.Menu;
import com.zeyu.framework.modules.sys.entity.Office;
import com.zeyu.framework.modules.sys.entity.Role;
import com.zeyu.framework.modules.sys.entity.User;
import com.zeyu.framework.utils.CacheUtils;
import com.zeyu.framework.utils.SpringContextHolder;
import com.zeyu.framework.utils.StringUtils;
import org.apache.shiro.session.Session;

import java.io.Serializable;
import java.util.List;
import java.util.Map;

public class UserUtils {

    // ================================================================
    // Constants
    // ================================================================

    /**
     * User Cache key
     */
    public static final String USER_CACHE = "userCache";
    public static final String USER_CACHE_ID_ = "id_";
    public static final String USER_CACHE_LOGIN_NAME_ = "ln";
    public static final String USER_CACHE_LIST_BY_OFFICE_ID_ = "oid_";

    public static final String CACHE_USER_ID_NAME_LIST = "userIdNameList";
    public static final String CACHE_ROLE_LIST = "roleList";
    public static final String CACHE_MENU_LIST = "menuList";
    public static final String CACHE_MENU_ROOT = "menu";
    public static final String CACHE_MENU_URL_MAP = "menuUrlMap";
    public static final String CACHE_OFFICE_LIST = "officeList";

    /**
     * 用户验证cache的key
     */
    public static final String VALIDATE_CODE_MAP = "loginFailMap";

    // ================================================================
    // Fields
    // ================================================================

    /**
     * 操作数据库dao
     */
    private static UserDao userDao = SpringContextHolder.getBean(UserDao.class);
    private static RoleDao roleDao = SpringContextHolder.getBean(RoleDao.class);
    private static MenuDao menuDao = SpringContextHolder.getBean(MenuDao.class);
    private static OfficeDao officeDao = SpringContextHolder.getBean(OfficeDao.class);

    // ================================================================
    // Constructors
    // ================================================================

    // ================================================================
    // Methods from/for super Interfaces or SuperClass
    // ================================================================

    // ================================================================
    // Public or Protected Methods
    // ================================================================

    /**
     * 根据ID获取用户
     *
     * @param id 用户id
     * @return 取不到返回null
     */
    public static User get(String id) {
        User user = (User) CacheUtils.get(USER_CACHE, USER_CACHE_ID_ + id);
        if (user == null) {
            user = userDao.get(id);
            if (user == null) {
                return null;
            }
            user.setRoleList(roleDao.findList(new Role(user)));
            CacheUtils.put(USER_CACHE, USER_CACHE_ID_ + user.getId(), user);
            CacheUtils.put(USER_CACHE, USER_CACHE_LOGIN_NAME_ + user.getLoginName(), user);
        }
        return user;
    }

    /**
     * 根据用户id获取用户名
     *
     * @param id 用户id
     * @return 获取不到返回默认
     */
    public static String getUserName(String id) {

        User user = get(id);
        if (user != null) {
            return user.getName();
        }
        return "admin";
    }

    /**
     * 根据登录名获取用户
     *
     * @param loginName 登录名
     * @return 取不到返回null
     */
    public static User getByLoginName(String loginName) {
        User user = (User) CacheUtils.get(USER_CACHE, USER_CACHE_LOGIN_NAME_ + loginName);
        if (user == null) {
            user = userDao.getByLoginName(new User(null, loginName));
            if (user == null) {
                return null;
            }
            user.setRoleList(roleDao.findList(new Role(user)));
            CacheUtils.put(USER_CACHE, USER_CACHE_ID_ + user.getId(), user);
            CacheUtils.put(USER_CACHE, USER_CACHE_LOGIN_NAME_ + user.getLoginName(), user);
        }
        return user;
    }

    /**
     * 清除当前用户缓存
     */
    public static void clearCache() {
        removeCache(CACHE_ROLE_LIST);
        removeCache(CACHE_MENU_LIST);
        removeCache(CACHE_MENU_ROOT);
        removeCache(CACHE_MENU_URL_MAP);
        removeCache(CACHE_OFFICE_LIST);
        removeCache(CACHE_USER_ID_NAME_LIST);
        UserUtils.clearCache(getUser());
    }

    /**
     * 清除指定用户缓存
     *
     * @param user 用户信息
     */
    public static void clearCache(User user) {
        CacheUtils.remove(USER_CACHE, USER_CACHE_ID_ + user.getId());
        CacheUtils.remove(USER_CACHE, USER_CACHE_LOGIN_NAME_ + user.getLoginName());
        CacheUtils.remove(USER_CACHE, USER_CACHE_LOGIN_NAME_ + user.getOldLoginName());
        if (user.getOffice() != null && user.getOffice().getId() != null) {
            CacheUtils.remove(USER_CACHE, USER_CACHE_LIST_BY_OFFICE_ID_ + user.getOffice().getId());
        }
    }

    /**
     * 获取当前用户
     *
     * @return 取不到返回 new User()
     */
    public static User getUser() {
        SystemAuthorizingRealm.Principal principal = SecurityUtils.getPrincipal();
        if (principal != null) {
            User user = get(principal.getId());
            if (user != null) {
                return user;
            }
            return new User();
        }
        // 如果没有登录，则返回实例化空的User对象。
        return new User();
    }

    /**
     * 获取当前用户列表
     *
     * @return 用户列表
     */
    public static List<Map<String, String>> getUserIdNameList() {
        @SuppressWarnings("unchecked")
        List<Map<String, String>> userIdNameList = (List<Map<String, String>>) getCache(CACHE_USER_ID_NAME_LIST);
        if (userIdNameList == null) {
            userIdNameList = Lists.newArrayList();
            List<User> users = userDao.findAllList(new User());
            if (users != null) {
                for (User user : users) {
                    Map<String, String> item = Maps.newHashMap();
                    item.put("id", user.getId());
                    item.put("name", user.getName());
                    userIdNameList.add(item);
                }
            }

            putCache(CACHE_USER_ID_NAME_LIST, userIdNameList);
        }
        return userIdNameList;
    }

    /**
     * 获取当前用户角色列表
     *
     * @return 角色列表
     */
    public static List<Role> getRoleList() {
        @SuppressWarnings("unchecked")
        List<Role> roleList = (List<Role>) getCache(CACHE_ROLE_LIST);
        if (roleList == null) {
            User user = getUser();
            if (user.isAdmin()) {
                roleList = roleDao.findAllList(new Role());
            } else {
                Role role = new Role();
                // 以后对角色进行部门分类可以在这里加逻辑
                roleList = roleDao.findList(role);
            }
            putCache(CACHE_ROLE_LIST, roleList);
        }
        return roleList;
    }

    /**
     * 获取当前用户授权菜单
     *
     * @return 用户授权菜单
     */
    public static List<Menu> getMenuList() {
        @SuppressWarnings("unchecked")
        List<Menu> menuList = (List<Menu>) getCache(CACHE_MENU_LIST);
        if (menuList == null) {
            User user = getUser();
            if (user.isAdmin()) {
                menuList = menuDao.findAllList(new Menu());
            } else {
                Menu m = new Menu();
                m.setUserId(user.getId());
                menuList = menuDao.findByUserId(m);
            }
            putCache(CACHE_MENU_LIST, menuList);
        }
        return menuList;
    }

    /**
     * 根据请求路径获取菜单
     */
    public static Menu getMenuByUri(String requestUri) {
        String href = StringUtils.substringAfter(requestUri, "");
        @SuppressWarnings("unchecked")
        Map<String, Menu> menuMap = (Map<String, Menu>) get(CACHE_MENU_URL_MAP);
        if (menuMap == null) {
            menuMap = Maps.newHashMap();
            // 获取菜单
            List<Menu> menuList = menuDao.findAllList(new Menu());
            for (Menu menu : menuList) {
                // 设置菜单名称路径
                if (menu != null && !menu.getId().equals(Menu.getRootId())) {
                    menuMap.put(menu.getHref(), menu);
                }
            }

            putCache(CACHE_MENU_URL_MAP, menuMap);
        }
        Menu menu = menuMap.get(href);
        if (menu == null) {
            menu = new Menu();
            menu.setIcon("fa fa-home fa-fw");
            menu.setName("My Dashboard");
            menu.setParentName("Dashboard");
        }

        return menu;
    }

    /**
     * 获取当前用户菜单-->包含子菜单
     *
     * @return 用户授权菜单
     */
    public static Menu getRootMenu() {
        @SuppressWarnings("unchecked")
        Menu root = (Menu) getCache(CACHE_MENU_ROOT);
        if (root == null) {
            // 根据用户权限获取菜单
            List<Menu> menuList = getMenuList();

            // 获取根节点
            for (Menu menu : menuList) {
                if (StringUtils.equals(menu.getId(), Menu.DEFAULT_ROOT_ID)) {
                    root = menu;
                    break;
                }
            }
            recursion(menuList, root);

            putCache(CACHE_MENU_ROOT, root);
        }
        return root;
    }

    /**
     * 获取当前用户有权限访问的部门
     *
     * @return 有权限访问的部门
     */
    public static List<Office> getOfficeList() {
        @SuppressWarnings("unchecked")
        List<Office> officeList = (List<Office>) getCache(CACHE_OFFICE_LIST);
        if (officeList == null) {
            User user = getUser();
            if (user.isAdmin()) {
                officeList = officeDao.findAllList(new Office());
            } else {
                Office office = new Office();
                // 以后对部门进行角色分类可以在这里加逻辑
                officeList = officeDao.findList(office);
            }
            putCache(CACHE_OFFICE_LIST, officeList);
        }
        return officeList;
    }

    /**
     * 是否是验证码登录
     *
     * @param username 用户名
     * @param isFail   计数加1
     * @param clean    计数清零
     * @return 验证码
     */
    @SuppressWarnings("unchecked")
    public static boolean isValidateCodeLogin(String username, boolean isFail, boolean clean) {
        Map<String, Integer> loginFailMap = (Map<String, Integer>) CacheUtils.get(VALIDATE_CODE_MAP);
        if (loginFailMap == null) {
            loginFailMap = Maps.newHashMap();
            CacheUtils.put(VALIDATE_CODE_MAP, (Serializable) loginFailMap);
        }
        Integer loginFailNum = loginFailMap.get(username);
        if (loginFailNum == null) {
            loginFailNum = 0;
        }
        if (isFail) {
            loginFailNum++;
            loginFailMap.put(username, loginFailNum);
        }
        if (clean) {
            loginFailMap.remove(username);
        }
        return loginFailNum >= 3;
    }

    /**
     * 根据office类型获取图标
     */
    public static String getIconByType(Office office) {
        if (office == null || office.getType() == null) {
            return "fa fa-map-marker";
        }
        // 机构类型（1：公司；2：部门；3：小组；4：其它）
        if (StringUtils.equals(office.getType(), "1")) {
            return "fa fa-home";
        } else if (StringUtils.equals(office.getType(), "2")) {
            return "fa fa-map-o";
        } else if (StringUtils.equals(office.getType(), "3")) {
            return "fa fa-flag-o";
        } else {
            return "fa fa-map-marker";
        }
    }

    /**
     * 根据menu获取图标
     */
    public static String getMenuIcon(Menu menu) {
        if (menu == null || StringUtils.isEmpty(menu.getIcon())) {
            return "fa fa-list-alt";
        }
        return menu.getIcon();
    }

    // ============== User Cache ==============

    public static Object getCache(String key) {
        return getCache(key, null);
    }

    public static Object getCache(String key, Object defaultValue) {
        // Object obj = getCacheMap().get(key);
        Object obj = null;
        Session session = SecurityUtils.getSession();
        if (session != null) {
            obj = session.getAttribute(key);
        }
        return obj == null ? defaultValue : obj;
    }

    public static void putCache(String key, Object value) {
        // getCacheMap().put(key, value);
        Session session = SecurityUtils.getSession();
        if (session != null) {
            session.setAttribute(key, value);
        }
    }

    public static void removeCache(String key) {
        // getCacheMap().remove(key);
        Session session = SecurityUtils.getSession();
        if (session != null) {
            session.removeAttribute(key);
        }
    }

    // ================================================================
    // Getter & Setter
    // ================================================================

    // ================================================================
    // Private Methods
    // ================================================================

    /**
     * 递归构建菜单和子菜单
     */
    private static void recursion(List<Menu> menuList, Menu root) {
        if (root != null) {
            List<Menu> childList = Lists.newArrayList();
            menuList.stream()
                    .filter(menu -> StringUtils.equals(menu.getParentId(), root.getId()))
                    .forEach(menu -> {
                        childList.add(menu);
                        recursion(menuList, menu);
                    });
            root.setChildList(childList);
        }
    }

    // ================================================================
    // Inner or Anonymous Class
    // ================================================================

    // ================================================================
    // Test Methods
    // ================================================================
}
